/*
Hermes Core: General Purpose Mobile Agent Platform
Copyright (C) 2006 UNICAM - Università degli Studi di Camerino

Group leaders: Flavio Corradini and Emanuela Merelli

Developers: Ezio Bartocci, Diego Bonura, Rosario Culmone,
Davide Lorenzoli, Leonardo Mariani, Francesca Piersigilli, 
Lorenzo Scortichini, Leonardo Vito.

GNU Lesser Public License

This library is free software; you can redistribute it 
and/or modify it under the terms of the GNU Lesser General 
Public License as published by the Free Software Foundation, 
version 2.1 of the License.

This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public 
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

Emanuela Merelli
Dipartimento di Matematica ed Informatica
Università di Camerino
via Madonna delle Carceri, 62032 Camerino, Italy
E.Mail: emanuela.merelli@unicam.it
*/
package hermesV2.basicServices.communication;

import hermesV2.Message;
import hermesV2.agent.Identificator;
import hermesV2.util.VectorQueue;

import java.io.Serializable;
import java.util.Vector;

/**
 * A message blocking queue based on java.util.Vector
 * @author Diego Bonura
 */
public final class MessageQueue<T extends Message<?>>  extends VectorQueue <T> implements Serializable
{

    /**
	 * 
	 */
	private static final long serialVersionUID = 1048847644910413938L;

	/**
     * Constructs a MessageQueue from a normal vector.
     * 
     * @param vector
     *            The vector
     */
    public MessageQueue(Vector<T> vector) {
        super(vector);
    }

    /**
     * Constructs an empty MessageQueue.
     */
    public MessageQueue() {
        this(new Vector<T>());
    }


    /**
     * Gets the message into the queue sent from a spacific agent, if the queue
     * is empty return null
     * 
     * @param senderIds
     *            The array of sender agents.
     * @return The message or null
     */

    public T poll(Identificator[] senderIds) {
        T o = null;
        synchronized (vector) {
            int i = 0;
            boolean found = false;
            while (i < vector.size() && !found) {
                int j = 0;
                while (j < senderIds.length && !found) {
                    if ((vector.elementAt(i)).getSenderAgentId().equals(senderIds[j])) {
                        found = true;
                    } else {
                        j++;
                    }
                }
                if (!found) {
                    i++;
                }
            }
            if (found) {
                o = vector.elementAt(i);
                vector.removeElementAt(i);
            }

        }

        return o;
    }

    /**
     * Gets the message into the queue sent from a spacific agent, if the queue
     * is empty return null
     * 
     * @param senderNames
     *            The sender agent name.
     * @return The message or null
     */

    public T poll(String[] senderNames) {
        T o = null;
        synchronized (vector) {
            int i = 0;
            boolean found = false;
            while (i < vector.size() && !found) {
                int j = 0;
                while (j < senderNames.length && !found) {
                    if ((vector.elementAt(i)).getSenderAgentId().getName().equals(senderNames[j])) {
                        found = true;
                    } else {
                        j++;
                    }
                }
                if (!found) {
                    i++;
                }
            }
            if (found) {
                o = vector.elementAt(i);
                vector.removeElementAt(i);
            }

        }

        return o;
    }



    /**
     * Returns the message sent from a specifica agent, if the message is not
     * present waits the threads until one notify
     * 
     * @return The message
     * @param senderIds
     *            The array of sender agents.
     * @throws InterruptedException
     */

    public T pull(Identificator[] senderIds) throws InterruptedException {
        return pull(0, senderIds);
    }

    /**
     * Returns the message sent from a specific agent, if the message is not
     * present waits the threads until one notify
     * 
     * @return The message
     * @param senderNames
     *            The array of sender agent name.
     * @throws InterruptedException
     */

    public T pull(String[] senderNames) throws InterruptedException {
        return pull(0, senderNames);
    }


    /**
     * Returns the message sent from a specifica agent, if the queue is empty
     * waits the threads until one notify or timeout expired
     * 
     * @param timeout
     *            The timeout
     * @param senderIds
     *            The array of sender agents.
     * @return The first message or null
     * @throws InterruptedException
     */
    public T pull(long timeout, Identificator[] senderIds) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout < 0");
        }

        long stopTime = System.currentTimeMillis() + timeout;

        T o = null;

        while ((o = poll(senderIds)) == null) {
            if (timeout == 0) {
                synchronized (vector) {
                    vector.wait();
                }
            } else {
                long now = System.currentTimeMillis();

                if (stopTime > now) {
                    synchronized (vector) {
                        vector.wait(stopTime - now);
                    }
                } else {
                    break;
                }
            }
        }

        return o;
    }

    /**
     * Returns the message sent from a specifica agent, if the queue is empty
     * waits the threads until one notify or timeout expired
     * 
     * @param timeout
     *            The timeout
     * @param senderNames
     *            The array of sender agent name.
     * @return The first message or null
     * @throws InterruptedException
     */
    public T pull(long timeout, String[] senderNames) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout < 0");
        }

        long stopTime = System.currentTimeMillis() + timeout;

        T o = null;

        while ((o = poll(senderNames)) == null) {
            if (timeout == 0) {
                synchronized (vector) {
                    vector.wait();
                }
            } else {
                long now = System.currentTimeMillis();

                if (stopTime > now) {
                    synchronized (vector) {
                        vector.wait(stopTime - now);
                    }
                } else {
                    break;
                }
            }
        }

        return o;
    }

}